# coding:utf-8
import sys

from datetime import datetime
from flask import current_app, jsonify
from flask import g
from flask import request
from flask import session

from iHome import constants
from iHome import redis_store, db
from iHome.api_1_0 import api
from iHome.constants import AREA_INFO_REDIS_EXPIRES, QINIU_DOMIN_PREFIX
from iHome.models import Area, House, Facility, HouseImage, Order
from iHome.utils.commons import login_required
from iHome.utils.image_storage import storage
from iHome.utils.response_code import RET

reload(sys)
sys.setdefaultencoding('utf-8')


@api.route('/areas')
def get_area_info():
    """
    查询城区信息
    # 0先到缓存中获取城区信息，如果没有再从数据库查询
    # 1.获取数据库中的所有信息
    # 2.组织字典数据返回
    # 3.把数据加载到缓存中
    # 4.返回响应
    """
    # 0先到缓存中获取城区信息，如果没有再从数据库查询
    try:
        areas = redis_store.get('area_info')
    except Exception as e:
        current_app.logger.error(e)
        areas = None
    if areas:
        print type(areas)
        return jsonify(errno=RET.OK, errmsg='获取成功', data=eval(areas))
    # 1.获取数据库中的所有信息
    try:

        areas = Area.query.all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询数据库失败')

    # 2.组织字典数据返回
    dict_area_info_list = list()
    for area in areas:
        dict_area_info_list.append(area.to_dict())

    # 3.把数据加载到缓存中
    redis_store.set('area_info', dict_area_info_list, AREA_INFO_REDIS_EXPIRES)
    # 4.返回响应
    return jsonify(errno=RET.OK, errmsg='获取成功', data=dict_area_info_list)


@api.route('/houses', methods=['POST'])
@login_required
def save_houses_info():
    """
    发布房源
    0.登陆验证
    1.接收参数
    2.效验参数
    3.初始化House，保存数据
    4.封装返回数据
    :return:
    """
    dict_data = request.get_json()
    print dict_data

    if not dict_data:
        return jsonify(errno=RET.PARAMERR, errmsg='参数接收失败')
    title = dict_data.get('title')
    price = dict_data.get('price')
    address = dict_data.get('address')
    area_id = dict_data.get('area_id')
    room_count = dict_data.get('room_count')
    acreage = dict_data.get('acreage')
    unit = dict_data.get('unit')
    capacity = dict_data.get('capacity')
    beds = dict_data.get('beds')
    deposit = dict_data.get('deposit')
    min_days = dict_data.get('min_days')
    max_days = dict_data.get('max_days')

    if not all(
            [title, price, address, area_id, room_count, acreage, unit, capacity, beds, deposit, min_days, max_days]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数错误')

    # 2效验价格的格式
    try:
        int(float(price) * 100)
        int(float(deposit) * 100)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg='参数失败')
    # 3.初始化House，保存数据
    house = House()
    house.user_id = g.user_id
    house.area_id = area_id
    house.title = title
    house.price = price
    house.address = address
    house.room_count = room_count
    house.acreage = acreage
    house.unit = unit
    house.capacity = capacity
    house.beds = beds
    house.deposit = deposit
    house.min_days = min_days
    house.max_days = max_days
    # 接收设施，列表类型
    facility = dict_data.get('facility')
    try:
        facilities = Facility.query.filter(Facility.id.in_(facility)).all()
        house.facilities = facilities
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询数据库失败')

    try:
        db.session.add(house)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg='保存到数据库失败')

    return jsonify(errno=RET.OK, errmsg='请求成功', data={'house_id': house.id})


@api.route('/houses/<int:house_id>/images', methods=['POST'])
@login_required  # 0.登陆验证
def upload_house_image(house_id):
    """
    上传房屋图片
    :param house_id: 房屋ID
    0.登陆验证
    1.接收前端传入参数 house_image
    2.验证参数
    3.查找House中的index_image_url字段，是否已经有图片，没有就添加
    4.上传到7牛云
    5.保存图片到HouseImage
    6.封装返回数据， 其牛云的前缀 + storage 返回的图片地址

    """
    print house_id, 45678967890
    # 1.接收前端传入参数 house_image
    house_file = request.files.get('house_image').read()

    # 2.验证参数
    if not house_file:
        return jsonify(errno=RET.NODATA, errmsg='未选择图片')

    # 3.查找House中的index_image_url字段，是否已经有图片，没有就添加
    # TODO 暂停吃饭 ^-^
    try:
        house = House.query.filter_by(id=house_id).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据库查找错误')
    if not house:
        return jsonify(errno=RET.NODATA, errmsg='查询错误')

    # 上传图片到7牛云
    try:
        image_name = storage(house_file)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.THIRDERR, errmsg='上传到七牛云失败')

    if not house.index_image_url:
        print 34567894567
        try:
            house.index_image_url = image_name
            db.session.add(house)
            db.session.commit()
        except Exception as e:

            current_app.logger.error(e)
    print house.index_image_url

    house_image = HouseImage()
    house_image.house_id = house_id
    house_image.url = image_name
    try:
        db.session.add(house_image)
        db.session.commit()

    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='保存房屋图片失败')

    image_url = QINIU_DOMIN_PREFIX + image_name
    print image_url
    return jsonify(errno=RET.OK, errmsg='上传成功', data={'url': image_url})


@api.route('/houses/<house_id>', methods=['GET'])  # 参数中的house_id不能设置为int类型，因为在存储到redis中时，str和int不能拼接
def house_detail(house_id):
    """
    房屋详情
    :param house_id:
    :return:
    """
    # 前端在房屋详情页面展示时，如果浏览页面的用户不是该房屋的房东，则展示预定按钮，否则不展示，
    # 所以需要后端返回登录用户的user_id
    # 尝试获取用户登录的信息，若登录，则返回给前端登录用户的user_id，否则返回user_id=-1

    # 判断参数是否有值
    print house_id
    if not house_id:
        return jsonify(errno=RET.PARAMERR, errmsg='参数缺失')

    user_id = session.get('user_id', -1)  # 如果用户登陆，返回user_id 如果未登陆就返回-1
    # 先从redis缓存中取
    try:
        house_info = redis_store.get('house_info_' + house_id)
    except Exception as e:
        house_info = None
        current_app.logger.error(e)

    # 如果有值,那么返回数据
    if house_info:
        current_app.logger.info('get house info from redis')
        return jsonify(errno=RET.OK, errmsg='OK', data={"user_id": user_id, "house": eval(house_info)})

    # 没有从缓存中取到,查询数据)库
    house = House.query.filter_by(id=house_id).first()
    if not house:
        return jsonify(errno=RET.NODATA, errmsg='未查询到房屋信息')

    # 将数据缓存到redis中
    house_dict = house.to_full_dict()
    try:
        redis_store.setex('house_info_' + house_id, constants.HOUSE_DETAIL_REDIS_EXPIRE_SECOND, house_dict)
    except Exception as e:
        current_app.logger.error(e)
    # 返回数据
    return jsonify(errno=RET.OK, errmsg='OK', data={"user_id": user_id, "house": house_dict})


@api.route('/houses/index')
def house_index():
    """
    获取首页推荐房屋信息
    :return:
    """

    # 先从redis中加载数据
    try:
        house_info = redis_store.get('home_page_house_info')
    except Exception as e:
        house_info = None
        current_app.logger.error(e)
    if house_info:
        return jsonify(errno=RET.OK, errmsg='OK', data=eval(house_info))

    # 从数组库中加载数据
    try:
        houses = House.query.order_by(House.order_count.desc()).limit(constants.HOME_PAGE_MAX_HOUSES).all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据查询失败')

    # 如果数据库中没有数据
    if not houses:
        return jsonify(errno=RET.NODATA, errmsg='未查询到数据')

    # 拼接到数组中
    houses_dict = []
    for house in houses:
        houses_dict.append(house.to_basic_dict())

    # 缓存到redis中
    try:
        redis_store.setex('home_page_house_info', constants.HOME_PAGE_DATA_REDIS_EXPIRES, houses_dict)
    except Exception as e:
        current_app.logger.error(e)

    # 返回数据
    return jsonify(errno=RET.OK, errmsg='OK', data=houses_dict)


@api.route('/houses', methods=['GET'])
def house_list():
    """
    首页搜索房屋
    :return:
    """

    # 获取所有的参数
    args = request.args
    area_id = args.get('aid', '')
    start_date_str = args.get('sd', '')
    end_date_str = args.get('ed', '')
    # booking(订单量), price-inc(低到高), price-des(高到低),
    sort_key = args.get('sk', 'new')  # new: 最新上线， booking: 入住最多， 价格:price-inc, price-des
    page = args.get('p', '1')

    # 打印参数
    print "area_id=%s,sd=%s,ed=%s,sk=%s,page=%s" % (area_id, start_date_str, end_date_str, sort_key, page)

    try:
        start_date = None
        end_date = None
        if start_date_str:
            start_date = datetime.datetime.strptime(start_date_str, '%Y-%m-%d')
        if end_date_str:
            end_date = datetime.datetime.strptime(end_date_str, '%Y-%m-%d')
        # 如果开始时间大于或者等于结束时间,就报错
        if start_date and end_date:
            assert start_date <= end_date, Exception('开始时间大于结束时间')
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg='参数错误')

    # 获取缓存
    redis_name = 'house_list_%s_%s_%s_%s' % (area_id, sort_key, start_date_str, end_date_str)
    try:
        resp = redis_store.hget(redis_name, page)
        if resp:
            pass
            # return jsonify(errno=RET.OK, errmsg='ok', data=eval(resp))
    except Exception as e:
        current_app.logger.error(e)

    # 查询数据
    try:
        # house_query = House.query
        if area_id:
            houses = House.query.filter(House.area_id == area_id)

        # 通过搜索时间去查询冲突的订单
        conflict_orders = []

        if start_date_str and end_date_str:
            conflict_orders = Order.query.filter(end_date_str > Order.begin_date, start_date_str < Order.end_date)

        if start_date_str:
            conflict_orders = Order.query.filter(start_date_str < Order.end_date)

        if end_date_str:
            conflict_orders = Order.query.filter(end_date_str > Order.begin_date)

        if conflict_orders:
            # 取到有冲突的订单的房屋id
            conflict_house_id = [order.house_id for order in conflict_orders]
            houses = House.query.filter(House.id.notin_(conflict_house_id))

        # 添加排序条件
        if sort_key == ' booking':
            houses = House.query.order_by(House.order_count.desc())

        if sort_key == 'price-inc':
            houses = House.query.order_by(House.price.asc())

        if sort_key == 'price-des':
            houses = House.query.order_by(House.price.desc())

        else:
            houses = House.query.order_by(House.create_time.desc())
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询数据库失败')
        # if not houses:
        # return jsonify(errno=RET., errmsg='')

    # houses = House.query.all()
    # 查询数据

    # 使用paginate进行分页
    house_pages = houses.paginate(int('1'), constants.HOUSE_LIST_PAGE_CAPACITY, False)
    # 获取当前页对象
    houses = house_pages.items
    # 获取总页数
    total_page = house_pages.pages
    # print total_page

    # 将查询结果转成字符串
    houses_dict = []
    for house in houses:
        houses_dict.append(house.to_basic_dict())

    # 将数据缓存到redis中
    resp = {"total_page": total_page, "houses": houses_dict}
    redis_name = 'house_list_%s_%s_%s_%s' % (area_id, sort_key, start_date_str, end_date_str)
    # 获得redis管道对象， 把所有要开启事务的事件都放到管道中，统一提交
    pipeline = redis_store.pipeline()
    try:
        # 开启事务

        pipeline.multi()
        # 设置数据
        pipeline.hset(redis_name, page, resp)
        # 设置过期时间
        pipeline.expire(redis_name, constants.HOUSE_LIST_REDIS_EXPIRES)

        # 提交事务
        pipeline.execute()

    except Exception as e:
        current_app.logger.error(e)

    return jsonify(errno=RET.OK, errmsg='请求成功', data=resp)
